home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
libs
/
oasys
/
oai.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-06
|
18KB
|
920 lines
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <time.h>
#include <bios.h>
#include <string.h>
#include <rwlib.h>
#include "ins.h"
const MAXWORDS = 64;
const MAXSTACK = 1024;
const MAXBUF = 512;
union var
{
int i;
dlist *o;
var *v;
};
struct phrase
{
int nwords;
int *words;
};
struct Class
{
int nphrases;
phrase *phrases;
};
struct instruction
{
int op;
int i;
};
struct method
{
int type;
int nargs;
int *argtypes;
int *selectors;
int nvars;
int *vartypes;
int nverbs;
phrase *verbs;
int noselect;
int ninstructions;
instruction *instructions;
};
int file;
char **strings;
var *vars;
int nvars;
int nproperties;
int nvocab;
char **vocab;
int comma;
int nwords;
int words[MAXWORDS];
var nouns[MAXWORDS];
char buf[MAXBUF];
char filename[MAXBUF] = "oasys.game";
Class *classes;
int nclasses;
int nmethods;
int initmethod;
method *methods;
int nnouns;
int selectaddresseemethod;
dlist objects;
var stack[MAXSTACK];
int sp;
int restart;
int *vartypes;
int *propertytypes;
var nullv;
inline void chkobject (dlist *o)
{
if (!o)
perr ("ERROR - Nonexistent object");
}
inline var *propertyptr (dlist *o,int i)
{
chkobject (o);
return ((var *)(((char *)o) + sizeof (dlist) + sizeof (int))) + i;
}
inline var *property (dlist *o,int i)
{
if (o == 0)
return &nullv;
return ((var *)(((char *)o) + sizeof (dlist) + sizeof (int))) + i;
}
inline int *classnoptr (dlist *o)
{
chkobject (o);
return (int *)(o+1);
}
inline int classno (dlist *o)
{
if (o == 0)
return -1;
return *((int *)(o+1));
}
readint ()
{
int i;
Read (file,&i,sizeof (int));
return i;
}
findvocab (char *s)
{
char **result = (char **)bsearch (&s,vocab,nvocab,sizeof (char*),strpcmp);
if (!result)
return -1;
return (int)(result - vocab);
}
int printx;
int printy;
void printnewline ()
{
putchar ('\n');
printx = 0;
printy++;
if (printy == 24)
{
printf ("MORE...");
bioskey (0);
printf ("\r \r");
printy = 0;
}
}
void printchar (int c)
{
static char buf[84];
static i;
switch (c)
{
case '\n':
case ' ':
if (printx+i > 78 && i <= 79)
printnewline ();
if (printx)
{
putchar (' ');
printx++;
}
buf[i] = 0;
printf ("%s",buf);
printx += i;
i = 0;
if (c == '\n')
printnewline ();
break;
default:
buf[i++] = c;
if (i == sizeof (buf))
perr ("ERROR - Word too long");
}
}
void print (char *s)
{
while (*s)
printchar (*s++);
}
void print (int i)
{
char s[12];
sprintf (s,"%d",i);
print (s);
}
void input (char *s)
{
printx = printy = 0;
gets (s);
}
void getinput ()
{
int i,j,k,c;
REDO:
print ("> ");
input (buf);
for (i=0 ; buf[i] ; i++)
if (buf[i] == '\t' || buf[i] == '\'' || buf[i] == '"')
buf[i] = ' ';
nwords = 0;
comma = -1;
for (i=0 ;;)
{
while (buf[i] == ' ')
i++;
if (!buf[i])
break;
if (buf[i] == ',')
{
if (comma >= 0)
{
print ("Commands should not have more than one comma.\n");
goto REDO;
}
comma = nwords;
i++;
continue;
}
j = i;
do
{
buf[j] = tolower (buf[j]);
j++;
}
while (buf[j] && buf[j] != ' ' && buf[j] != ',');
c = buf[j];
buf[j] = 0;
if (strcmp (buf+i,"the"))
{
if (buf[i] == '-')
{
print ("Negative numbers not implemented.\n");
goto REDO;
}
if (isdigit (buf[i]))
words[nwords++] = ~atoi (buf+i);
else
{
k = findvocab (buf+i);
if (k < 0)
{
print ("I don't understand the word \"");
print (buf+i);
print ("\".\n");
goto REDO;
}
if (nwords == MAXWORDS)
{
print ("There were too many words in that command.\n");
goto REDO;
}
words[nwords++] = k;
}
}
buf[j] = c;
i = j;
}
}
findclass (int *words,int nwords)
{
int i,j;
for (i=0 ; i<nclasses ; i++)
for (j=0 ; j<classes[i].nphrases ; j++)
if (nwords == classes[i].phrases[j].nwords &&
!memcmp (words,classes[i].phrases[j].words,nwords * sizeof (int)))
return i;
return -1;
}
void writeint (int i)
{
Write (file,&i,sizeof (int));
}
void writevars (int n,var *vars,int *vartypes)
{
dlist *o;
int i;
do
{
var v = *vars;
if (*vartypes == T_OBJECT)
{
for (o=objects.next,i=0 ; o!=&objects ; o=o->next,i++)
if (v.o == o)
{
v.i = i;
break;
}
if (o == &objects)
v.i = -1;
}
Write (file,&v,sizeof (v));
vars++;
vartypes++;
}
while (--n > 0);
}
void savegame ()
{
dlist *o;
print ("File name? [");
print (filename);
print ("] ");
input (buf);
if (buf[0] == 0)
strcpy (buf,filename);
file = open (buf,O_RDWR | O_BINARY | O_CREAT | O_TRUNC,0777);
if (file < 0)
{
print ("Can't create file.\n");
return;
}
strcpy (filename,buf);
Write (file,"oas\1",4);
writevars (nvars,vars,vartypes);
writeint (objects.len ());
for (o=objects.next ; o!=&objects ; o=o->next)
{
writeint (*classnoptr (o));
writevars (nproperties,propertyptr (o,0),propertytypes);
}
close (file);
}
void chkvars (int n,var *vars,int *vartypes,dlist *o)
{
do
{
if (*vartypes == T_OBJECT && vars->o == o)
vars->o = 0;
vars++;
vartypes++;
}
while (--n > 0);
}
void restorevars (int n,var *vars,int *vartypes)
{
dlist *o;
int i;
do
{
if (*vartypes == T_OBJECT)
{
if (vars->i < 0)
vars->o = 0;
else
{
for (o=objects.next,i=0 ; i!=vars->i ; o=o->next,i++)
assert (o!=&objects);
vars->o = o;
}
}
vars++;
vartypes++;
}
while (--n > 0);
}
loadgame ()
{
int i;
char gamecode[4];
dlist *o;
print ("File name? [");
print (filename);
print ("] ");
input (buf);
if (buf[0] == 0)
strcpy (buf,filename);
file = open (buf,O_RDWR | O_BINARY);
if (file < 0)
{
print ("Can't open file.\n");
return FALSE;
}
Read (file,gamecode,4);
if (memcmp (gamecode,"oas\1",4))
{
print ("Not a saved position for this game.\n");
close (file);
return FALSE;
}
strcpy (filename,buf);
objects.free ();
Read (file,vars,nvars * sizeof (var));
i = readint ();
do
{
o = (dlist *)new char[sizeof (dlist) + sizeof (int) +
nproperties * sizeof (var)];
memset (((char *)o) + sizeof (dlist) + sizeof (int),0,
nproperties * sizeof (var));
*classnoptr (o) = readint ();
Read (file,propertyptr (o,0),nproperties * sizeof (var));
objects += o;
}
while (--i > 0);
close (file);
restorevars (nvars,vars,vartypes);
for (o=objects.next ; o!=&objects ; o=o->next)
restorevars (nproperties,propertyptr (o,0),propertytypes);
return TRUE;
}
getyn (char *s)
{
for (;;)
{
print (s);
input (buf);
if (buf[0] == 'y' || buf[0] == 'Y')
return TRUE;
if (buf[0] == 'n' || buf[0] == 'N')
return FALSE;
}
}
var applymethod (dlist *o,int methodno,var *argv)
{
var v;
int pc;
dlist *o2,*o3;
instruction I;
int i;
if (o == 0 && methodno != initmethod)
return nullv;
method *m = &methods[methodno];
int bp = sp;
memset (stack+bp,0,m->nvars + sizeof (var));
sp += m->nvars;
for (pc=0 ; pc!=m->ninstructions ; pc++)
{
assert (sp >= 0);
if (sp >= MAXSTACK)
perr ("ERROR - Stack overflow");
I = m->instructions[pc];
switch (I.op)
{
case I_JMP:
pc += I.i;
break;
case I_JF:
if (!stack[--sp].i)
pc += I.i;
break;
case I_JT:
if (stack[--sp].i)
pc += I.i;
break;
case I_INT:
stack[sp++].i = I.i;
break;
case I_OR:
sp--;
stack[sp-1].i = stack[sp-1].i || stack[sp].i;
break;
case I_AND:
sp--;
stack[sp-1].i = stack[sp-1].i && stack[sp].i;
break;
case I_NOT:
stack[sp-1].i = !stack[sp-1].i;
break;
case I_REFLOCALVAR:
stack[sp++].v = stack + bp + I.i;
break;
case I_REFARG:
stack[sp++].v = argv + I.i;
break;
case I_REFGLOBALVAR:
stack[sp++].v = vars + I.i;
break;
case I_REFPROPERTY:
stack[sp-1].v = property (stack[sp-1].o,I.i);
break;
case I_DEREF:
stack[sp-1] = *stack[sp-1].v;
break;
case I_CALLPROC:
applymethod (stack[sp - methods[I.i].nargs - 1].o,I.i,
stack + sp - methods[I.i].nargs);
if (restart)
return nullv;
sp -= methods[I.i].nargs + 1;
break;
case I_CALLFUNC:
v = applymethod (stack[sp - methods[I.i].nargs - 1].o,I.i,
stack + sp - methods[I.i].nargs);
if (restart)
return nullv;
sp -= methods[I.i].nargs + 1;
stack[sp++] = v;
break;
case I_ASSIGN:
sp -= 2;
*stack[sp].v = stack[sp+1];
break;
case I_DESTROY:
o2 = stack[--sp].o;
chkobject (o2);
o2->remove ();
for (o3=objects.next ; o3!=&objects ; o3=o3->next)
chkvars (nproperties,propertyptr (o3,0),propertytypes,o2);
chkvars (nvars,vars,vartypes,o2);
break;
case I_CREATE:
o2 = (dlist *)new char[sizeof (dlist) + sizeof (int) +
nproperties * sizeof (var)];
memset (((char *)o2) + sizeof (dlist) + sizeof (int),0,
nproperties * sizeof (var));
*classnoptr (o2) = I.i;
objects += o2;
stack[sp++].o = o2;
break;
case I_QUIT:
if (!getyn ("Are you sure? (Y/N) "))
break;
case I_EXIT:
restart = TRUE;
return nullv;
case I_THIS:
stack[sp++].o = o;
break;
case I_RETFUNC:
v = stack[--sp];
case I_RETPROC:
assert (sp == bp+m->nvars);
sp = bp;
return v;
case I_EXISTS:
stack[sp-1].i = (stack[sp-1].o != 0);
break;
case I_OBJECT:
o2 = 0;
i = stack[sp-1].i;
if (i > 0)
{
for (o2=objects.next ; i>1 && o2!=&objects ; o2=o2->next,i--)
;
if (i > 1)
o2 = 0;
}
stack[sp-1].o = o2;
break;
case I_PRINTINT:
print (stack[--sp].i);
break;
case I_PRINTSTR:
print (strings[stack[--sp].i]);
break;
case I_SAVE:
savegame ();
break;
case I_LOAD:
stack[sp++].i = loadgame ();
break;
case I_MINUS:
stack[sp-1].i = -stack[sp-1].i;
break;
case I_ADD:
sp--;
stack[sp-1].i = stack[sp-1].i + stack[sp].i;
break;
case I_SUB:
sp--;
stack[sp-1].i = stack[sp-1].i - stack[sp].i;
break;
case I_MUL:
sp--;
stack[sp-1].i = stack[sp-1].i * stack[sp].i;
break;
case I_DIV:
sp--;
if (!stack[sp].i)
perr ("ERROR - Division by zero");
stack[sp-1].i = stack[sp-1].i / stack[sp].i;
break;
case I_MOD:
sp--;
if (!stack[sp].i)
perr ("ERROR - Division by zero");
stack[sp-1].i = stack[sp-1].i % stack[sp].i;
break;
case I_EQ:
sp--;
stack[sp-1].i = stack[sp-1].i == stack[sp].i;
break;
case I_NE:
sp--;
stack[sp-1].i = stack[sp-1].i != stack[sp].i;
break;
case I_GT:
sp--;
stack[sp-1].i = stack[sp-1].i > stack[sp].i;
break;
case I_LT:
sp--;
stack[sp-1].i = stack[sp-1].i < stack[sp].i;
break;
case I_GE:
sp--;
stack[sp-1].i = stack[sp-1].i >= stack[sp].i;
break;
case I_LE:
sp--;
stack[sp-1].i = stack[sp-1].i <= stack[sp].i;
break;
case I_OEQ:
sp--;
stack[sp-1].i = stack[sp-1].o == stack[sp].o;
break;
case I_ONE:
sp--;
stack[sp-1].i = stack[sp-1].o != stack[sp].o;
break;
case I_RANDOM:
if (!stack[sp-1].i)
perr ("ERROR - Division by zero");
stack[sp-1].i = rand () % stack[sp-1].i;
break;
case I_IS:
stack[sp-1].i = (classno (stack[sp-1].o) == I.i);
break;
case I_NEXT:
if (stack[sp-1].o)
if ((stack[sp-1].o = stack[sp-1].o->next) == &objects)
stack[sp-1].o = 0;
break;
default:
assert (FALSE);
}
}
assert (sp == bp+m->nvars);
sp = bp;
return nullv;
}
dlist *nountoobject (int n,int methodno)
{
dlist *o;
for (o=objects.next ; o!=&objects ; o=o->next)
if (*classnoptr (o) == n)
{
if (methodno < 0)
return o;
var v = applymethod (o,methodno,0);
if (v.i)
return o;
}
return 0;
}
void docommand (int addressee,int methodno)
{
int i;
dlist *ad = vars[0].o;
if (addressee >= 0)
if (selectaddresseemethod >= 0)
{
ad = nountoobject (addressee,selectaddresseemethod);
if (ad == 0)
{
if (methods[selectaddresseemethod].noselect >= 0)
print (strings[methods[selectaddresseemethod].noselect]);
else
print ("You can't talk to that.\n");
return;
}
}
else
{
print ("You can't talk to that.\n");
return;
}
for (i=0 ; i<nnouns ; i++)
if (methods[methodno].argtypes[i] == T_OBJECT)
{
nouns[i].o = nountoobject (nouns[i].i,methods[methodno].selectors[i]);
if (nouns[i].o == 0)
{
if (methods[methods[methodno].selectors[i]].noselect >= 0)
print (strings[methods[methods[methodno].selectors[i]].noselect]);
return;
}
}
applymethod (ad,methodno,nouns);
}
void command ()
{
int firstword,addressee,thisword,wordsleft,vwordsleft,vword,nounwords;
int noun,i,j,k,argno;
REDO:
getinput ();
firstword = 0;
addressee = -1;
if (comma >= 0)
{
if (comma == 0)
{
print ("I don't know who you're trying to talk to.\n");
goto REDO;
}
addressee = findclass (words,comma);
if (addressee < 0)
{
print ("I don't know who you're trying to talk to.\n");
goto REDO;
}
nwords -= firstword = comma;
}
for (i=0 ; i<nmethods ; i++)
if (methods[i].nverbs)
for (j=0 ; j<methods[i].nverbs ; j++)
{
thisword = firstword;
wordsleft = nwords;
vwordsleft = methods[i].verbs[j].nwords;
nnouns = 0;
argno = 0;
for (k=0 ;; k++)
{
if (wordsleft == 0)
{
if (k == methods[i].verbs[j].nwords)
{
docommand (addressee,i);
return;
}
break;
}
if (k == methods[i].verbs[j].nwords)
break;
vwordsleft--;
vword = methods[i].verbs[j].words[k];
if (vword >= 0)
{
if (vword != words[thisword])
break;
thisword++;
wordsleft--;
}
else
{
if (methods[i].argtypes[argno++] == T_INT)
{
if (words[thisword] >= 0)
break;
nouns[~vword].i = ~words[thisword];
thisword++;
wordsleft--;
}
else
{
nounwords = 0;
do
{
nounwords++;
if (nounwords+vwordsleft > wordsleft)
break;
noun = findclass (words+thisword,nounwords);
}
while (noun < 0);
if (noun < 0)
break;
nouns[~vword].i = noun;
thisword += nounwords;
wordsleft -= nounwords;
}
nnouns = Max (nnouns,-vword);
}
}
}
print ("I don't understand you.\n");
goto REDO;
}
main (int argc,char **argv)
{
int n,i,j,k;
if (argc != 2 || !strcmp (argv[1],"?"))
perr ("Object-Oriented Adventure Interpreter" VERSION "\n"
"Usage: oai filename");
randomize ();
file = Open (argv[1]);
Read (file,buf,4);
if (memcmp (buf,"oas",4))
perr ("Not an OASYS file");
n = readint ();
strings = new char *[n];
for (i=0 ; i<n ; i++)
{
j = readint ();
strings[i] = new char[j+1];
Read (file,strings[i],j);
strings[i][j] = 0;
}
nvars = readint ();
vars = new var[nvars];
vartypes = new int[nvars];
Read (file,vartypes,nvars * sizeof (int));
nproperties = readint ();
propertytypes = new int[nproperties];
Read (file,propertytypes,nproperties * sizeof (int));
nvocab = readint ();
vocab = new char *[nvocab];
for (i=0 ; i<nvocab ; i++)
{
j = readint ();
vocab[i] = new char[j+1];
Read (file,vocab[i],j);
vocab[i][j] = 0;
}
nclasses = readint ();
classes = new Class[nclasses];
for (i=0 ; i<nclasses ; i++)
{
int nphrases = readint ();
classes[i].nphrases = nphrases;
if (nphrases)
{
classes[i].phrases = new phrase[nphrases];
for (j=0 ; j<nphrases ; j++)
{
k = readint ();
classes[i].phrases[j].nwords = k;
classes[i].phrases[j].words = new int[k];
Read (file,classes[i].phrases[j].words,k * sizeof (int));
}
}
}
nmethods = readint ();
methods = new method[nmethods];
initmethod = readint ();
selectaddresseemethod = readint ();
for (i=0 ; i<nmethods ; i++)
{
method *m = &methods[i];
m->type = readint ();
j = readint ();
m->nargs = j;
if (j)
{
m->argtypes = new int[j];
m->selectors = new int[j];
for (k=0 ; k<j ; k++)
{
m->argtypes[k] = readint ();
m->selectors[k] = readint ();
}
}
m->nvars = readint ();
if (m->nvars)
{
m->vartypes = new int[m->nvars];
Read (file,m->vartypes,m->nvars * sizeof (int));
}
int nverbs = readint ();
m->nverbs = nverbs;
if (nverbs)
{
m->verbs = new phrase[nverbs];
for (j=0 ; j<nverbs ; j++)
{
k = readint ();
m->verbs[j].nwords = k;
m->verbs[j].words = new int[k];
Read (file,m->verbs[j].words,k * sizeof (int));
}
}
m->noselect = readint ();
k = readint ();
m->ninstructions = k;
if (k)
{
m->instructions = new instruction[k];
Read (file,m->instructions,k * sizeof (instruction));
}
}
close (file);
memset (vars,0,nvars * sizeof (var));
applymethod (0,initmethod,0);
for (;;)
{
assert (sp == 0);
command ();
if (restart)
{
if (!getyn ("Would you like to play again? (Y/N) "))
return 0;
objects.free ();
sp = 0;
memset (vars,0,nvars * sizeof (var));
restart = FALSE;
applymethod (0,initmethod,0);
}
}
}